E-istio-csr 사용 실습

개요

메시 배포 모델을 보면 여러 클러스터 구성 시 클러스터 간 공통 CA를 두어야 하는 이슈가 생긴다.
이는 곧 컨트롤 플레인의 CA로서의 기능을 포기시키는 것과 같다.

이때 두 가지 방법이 있는데, 첫번째는 Plugin CA이다.
이 방식은 istiod가 그대로 인증서 발급 서버로 동작하긴 하되, 중간 체인 서버로서 기능한다.
즉 미리 사전에 여러 istiod들이 공유할 루트 CA를 두고, 이를 기반으로 각 istiod가 중간 체인 서버로 기능하는 것이다.

이와 또다른 방식으로 아예 istiod를 CA로부터 분리시키는 방법이 있다.
인증서를 발급하는 역할을 완전히 외부로 독립시키고 istiod는 메시를 구성하는 업무만 수행하게 만드는 것이다.

이때 매우 유용하게 사용할 수 있는 솔루션 중 하나인 istio-csr에 대해 실습해본다.

istio-csr

istio-csr은 사실 Cert Manager 측에서 제공하는 이스티오에 호환되는 인증서 서버 어댑터이다.[1]
서트 매니저의 인증서를 이용해 인증서를 발행해주는 기능을 가지고 있다.
구체적으로는 이스티오 인증 서비스를 gRPC로 구현하여 모든 메시 내 서비스를 위한 인증서를 처리해준다.

세 가지 컴포넌트를 가지고 있다.[^1]

발급 흐름, 세팅 시 정보

구체적인 인증서 발급 흐름은 다음과 같다.

istio csr은 처음 구동될 때부터 이슈어 정보를 필요로 한다.
이때 이슈어를 세팅하는 방법은 여러가지가 있다.

알아서 이슈어를 만드는 게 가장 순수한 런타임 설정이라 할 수 있겠다.

단일 클러스터를 위한 설치

기본 예제에 나온 대로 실습을 먼저 해본다.[2]
이 세팅에서는 다음의 순서대로 세팅을 진행한다.

당연하지만 istio-csr은 반드시 이스티오보다 먼저 설치돼야 한다.
이스티오에 인증서를 제공자로서 동작하기 때문이다.

helm repo add jetstack https://charts.jetstack.io --force-update
helm install \
  cert-manager jetstack/cert-manager \
  --wait \
  --namespace cert-manager \
  --create-namespace \
  --version v1.17.2 \
  --set crds.enabled=true \
  --kubeconfig=./west-kubeconfig

cat << EOF | kubectl apply --kubeconfig=./west-kubeconfig -f -
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: selfsigned
  namespace: istio-system
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: istio-ca
  namespace: istio-system
spec:
  isCA: true
  duration: 87600h # 10 years
  secretName: istio-ca
  commonName: istio-ca
  privateKey:
    algorithm: ECDSA
    size: 256
  subject:
    organizations:
    - cluster.local
    - cert-manager
  issuerRef:
    name: selfsigned
    kind: Issuer
    group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: istio-ca
  namespace: istio-system
spec:
  ca:
    secretName: istio-ca
EOF

kwest -n istio-system wait --for create secret istio-ca --timeout=60s
kwest get -n istio-system secret istio-ca -ogo-template='{{index .data "tls.crt"}}' | base64 -d > ca.pem
kwest create secret generic -n cert-manager istio-root-ca --from-file=ca.pem=ca.pem

helm upgrade cert-manager-istio-csr jetstack/cert-manager-istio-csr \
  --install \
  --namespace cert-manager \
  --wait \
  --set "app.tls.rootCAFile=/var/run/secrets/istio-csr/ca.pem" \
  --set "volumeMounts[0].name=root-ca" \
  --set "volumeMounts[0].mountPath=/var/run/secrets/istio-csr" \
  --set "volumes[0].name=root-ca" \
  --set "volumes[0].secret.secretName=istio-root-ca" \
  --set "service.type=LoadBalancer" \
  --set "app.server.clusterID=west-cluster" \
  --kubeconfig=./west-kubeconfig

정적 파일로 전달하는 방법을 첫번째로 소개하길래 그대로 이용했다.

처음 세팅을 진행하고 로그를 확인해보면..

kubectl logs -n cert-manager $(kubectl get pods -n cert-manager -o jsonpath='{.items..metadata.name}' --selector app=cert-manager) --since 2m -f
kubectl get certificaterequests.cert-manager.io -n istio-system -w

image.png
보다시피 CA bundle distributor가 모든 네임스페이스에 시크릿을 만들고 있다.

kwest get cm istio-ca-root-cert -ojsonpath='{.data.root-cert\.pem}' | openssl x509 -noout -text

image.png
내용물을 뜯어보면 그냥 CA 인증서를 모든 네임스페이스에 휘갈긴다.

이스티오 설치 후 확인

cat << EOF | istioctl install --kubeconfig=./west-kubeconfig -f - -y
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: istio-system
spec:
  profile: default
  meshConfig:
    trustDomain: cluster.local
  values:
    global:
      # istio-csr
      caAddress: cert-manager-istio-csr.cert-manager.svc:443
      meshID: usmesh
      multiCluster:
        clusterName: west-cluster
      network: west-network
  components:
    pilot:
      k8s:
        env:
          - name: ENABLE_CA_SERVER
            value: "false"
EOF

다음으로 이스티오를 설치하는데, 이때 istiod의 환경변수로 CA 서버를 비활성화하고 caAddress를 설정해야만 한다.
values 필드는 헬름 양식으로 설정되는 부분들인데 global 부분은 이스티오의 모든 컴포넌트 파드에 적용된다.
meshConfig에 해당 설정 부분이 있을 줄 알고 열심히 찾았는데 values를 통해서 설정할 수밖에 없더라..

image.png
먼저 istiod의 로그를 보면 인증서를 로딩하는 과정을 살펴볼 수 있다.
이 설정 상에서 istiod는 인증서 발급과정을 그냥 istio csr에게 완전히 위임해버린다.

아무 워크로드나 배포해보자.
image.png
주입된 프록시를 보면 환경변수로 CA의 주소가 istio csr로 찍히는 것이 확인된다.
image.png
프록시의 로그를 살펴보면 CA 엔드포인트가 실제로 istio csr로 설정된다.
이 설정은 istiod를 인증서 발급 플로우에서 완전히 제외시켜버리는 듯하다.

아쉽게도 관련한 로그를 istio csr 측에서는 기본으로 제공하지 않는다.
image.png
대신 워크로드가 만들어질 때 서트매니저의 로그를 보면 인증서를 승인하고 발급해주는 구조가 들어가는 것을 확인할 수 있다.

실제 인증서는 어떻게 나왔을까?

iwest -n istioinaction pc secret debug -ojson | jq '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -noout -text

image.png
발급자의 정보는 처음에 만들었던 cert manager의 이슈어 리소스에 들어간 설정으로 들어간다.
image.png
그리고 SAN에 이스티오에서 요구되는 SVID가 들어간 것을 확인할 수 있다.

이제 CA가 istiod로부터 외부화되었기 때문에, 한 가지 문제가 생긴다.
바로 istiod와 프록시 간 통신에서 istiod를 검증하는 것이다.
다행히도 istio csr은 istiod를 위한 인증서를 발급하는 것도 까먹지 않는다!

kwest describe certificate -n istio-system istiod 

image.png
Certificate 리소스를 확인해보면 istiod를 위한 인증서가 들어가있는 것을 확인할 수 있다.
30분 주기로 갱신되는 것을 확인할 수 있다.
image.png
위에서 봤던 로그를 다시보면 Pilot SAN: [istiod.istio-system.svc]가 보이는데, istiod에 대한 정보를 여기에서 받게 되는 것이다.

istio-csr을 단일 클러스터에서 사용하는 건 굉장히 쉽다!

주의 - 멀티 클러스터에서 mtls를 위한 클러스터 id

istio-csr이 있다고 해서 이것이 여러 클러스터의 인증서를 관리하는 기능을 제공할 것이라 생각하면 곤란하다.
왜냐하면 istio csr 헬름 세팅 시 이 부분이 이스티오 클러스터 이름과 무조건 일치해야 하기 때문이다.

  --set "app.server.clusterID=west-cluster" 

image.png
처음에 이 부분을 캐치 못하고 세팅해서 에러가 계속 발생했다.
image.png
간단하게 아무 파드를 만들었을 때도 역시 ca 서버로부터 인증서를 받아오지 못하는 것을 볼 수 있다.

예제로 할 때는 문제가 없는데, 추가 설정을 넣기만 하면 문제가 생기는 걸 보고 에러를 조금 더 자세히 들여다봤다.
인증 과정 상에서 문제가 발생하는데, 아무래도 통신하는 상대를 검증할 때 문제가 발생하는 게 아닐까?
아무래도 meshId, 혹은 클러스터 이름 관련해서 문제가 생기는 게 아닐까 싶다.
image.png
istio csr은 istiod와 통신할 때 상대의 cluster id를 확인한다.
그렇기 때문에 cluster 이름을 수정하면 영향을 받게 된다.
달리 말해, istio csr은 단일 클러스터에 대해서만 인증서 관리를 해줄 수 있다는 말이다.

멀티 클러스터를 위한 인증서 솔루션

한 클러스터를 기준으로 동작하는 istio-csr, cert-manager는 멀티 클러스터 기능을 단독을 제공해줄 수 없다.
서트 매니저는 클러스터 별로 인증서를 관리하는 목적의 툴이기에 각각 있는 것이 이상하진 않다.
그렇다면 서트 매니저에게 인증서를 공급해주는 별도의 솔루션이 필요하다.

가능한 선택지는 이 정도가 있다.

볼트와 스파이어를 연동해서 활용하는 방법도 있긴 한 것 같다.
볼트에서 SVID를 제공할 수 있는가?
볼트를 SVID를 이용하여 인증하고 시크릿을 가져오는 것들에 대한 예제와 솔루션은 있는 것으로 보인다.[3][4]
그러나 볼트에서 역을 지원하진 않는 것으로 보인다.

vault, istio-csr

볼트와 istio-csr을 연동해 사용할 경우의 흐름은 이 정도로 정리할 수 있겠다.

마침 보니 비슷한 글이 보인다.[5]
볼트를 바로 istio와 연동하여 활용하려면 istiod 파드에 볼트 에이전트를 주입하여 관리하는 방식이 가능하다.[6]

최종적으로는 볼트를 root CA로 두고, istio csr을 이용하는 방향으로 정했다.
가장 첫번째 이유는 볼트도, cert manager도 사용해봤기 때문.
spire는 사용해본 적이 없었고 아직 숙련도가 충분하지 않다고 판단했다.
아는 한에서 spire는 스피페 양식의 신원을 제공하는 것 이외의 큰 메리트는 없다.
볼트 에이전트를 활용하는 방식은 istio에서 인지하지 못하는 의존성이 추가된다는 것이 아쉽다고 생각한다.
여기에 에이전트 방식은 어노테이션을 자질구레하게 많이 달아야 한다는 것도 실수를 하기 딱 좋다.
사실 그냥 가장 익숙해보여서 하는 거임

관련 문서

지식 문서, EXPLAIN

이름5is-folder생성 일자
E-앰비언트 모드에서 메시 기능 활용false2025-06-07 20:56
Istio Securitytrue2025-05-04 19:58
Istio RequestAuthenticationfalse2025-05-04 20:16
Istio PeerAuthenticationfalse2025-05-04 20:00
Istio AuthorizationPolicyfalse2025-05-04 20:19

기타 문서

Z0-연관 knowledge, Z1-트러블슈팅 Z2-디자인,설계, Z3-임시, Z5-프로젝트,아카이브, Z8,9-미분류,미완
이름3코드타입생성 일자
5W - 이스티오 JWT 인증Z8published2025-05-11 00:03
5W - 이스티오 mTLS와 SPIFFEZ8published2025-05-11 00:01
5W - 이스티오 인가 정책 설정Z8published2025-05-11 00:04

참고


  1. https://cert-manager.io/docs/usage/istio-csr/ ↩︎

  2. https://cert-manager.io/docs/usage/istio-csr/installation/ ↩︎

  3. https://github.com/philips-labs/spiffe-vault?tab=readme-ov-file ↩︎

  4. https://spiffe.io/docs/latest/keyless/vault/readme/ ↩︎

  5. https://medium.com/@espinaladrinaldi/istio-multicluster-with-istio-csr-cert-manager-vault-pki-66c2d58f1c7f ↩︎

  6. https://tetrate.io/blog/how-to-use-hashicorp-vault-as-a-more-secure-way-to-store-istio-certificates/ ↩︎